package vip.youngboy.freejump.command;

import org.activiti.bpmn.model.Activity;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.delegate.event.ActivitiEventDispatcher;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.activiti.engine.impl.cmd.NeedsActiveTaskCmd;
import org.activiti.engine.impl.history.HistoryManager;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;

import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * 自由跳转命令类
 */
public class FreeJumpCommand extends NeedsActiveTaskCmd<Void> {

    /**
     * 目标节点
     */
    protected String destination;

    /**
     * 流程实例id
     */
    protected String parentId;

    /**
     * 流程变量
     */
    protected Map<String, Object> variables;

    /**
     * 是否为局部变量
     */
    protected Boolean localScope;

    public FreeJumpCommand(String taskId, String destination, String parentId, Map<String, Object> variables, Boolean localScope) {
        super(taskId);
        this.destination = destination;
        this.parentId = parentId;
        this.variables = variables;
        this.localScope = localScope;
    }

    @Override
    protected Void execute(CommandContext commandContext, TaskEntity task) {

        //获取对应的流程实例
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
        String excutionId = task.getExecutionId();
        ExecutionEntity executionEntity = executionEntityManager.findById(excutionId);
        //获取流程定义id
        String processDefinitionId = task.getProcessDefinitionId();
        Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
        //获取目标任务节点
        FlowElement targetElement = process.getFlowElement(destination);
        Activity targetActivity = (Activity) targetElement;
        Object behavior = targetActivity.getBehavior();
        if (behavior instanceof MultiInstanceActivityBehavior) {
            //多实例节点
            doMultiNodeJump(executionEntity, task, targetElement, commandContext);
        } else {
            doNormalNodeJump(executionEntity, task, targetElement, commandContext);
        }

        return null;
    }


    /**
     * 多实例节点跳转
     *
     * @param executionEntity 执行实例
     * @param task            任务实体
     * @param targetElement   目标节点
     * @param commandContext  命令上下文
     */
    private void doMultiNodeJump(ExecutionEntity executionEntity, TaskEntity task, FlowElement targetElement, CommandContext commandContext) {
        ExecutionEntity topEntity = getTopEntityManager(executionEntity);
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
        HistoryManager historyManager = commandContext.getHistoryManager();
        String processId = topEntity.getProcessInstanceId();
        TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
        List<TaskEntity> tasks = taskEntityManager.findTasksByProcessInstanceId(processId);
        //删除流程实例下的所有任务
        Iterator<TaskEntity> iterator = tasks.iterator();
        while (iterator.hasNext()) {
            TaskEntity taskItem = iterator.next();
            //触发监听事件
            dispatcherEvent(commandContext, taskItem, false);
            //删除任务
            taskEntityManager.deleteTask(taskItem.getId(), "自由跳转", false);
        }
        //删除子执行实例
        List<ExecutionEntity> childExecutions = executionEntityManager.findChildExecutionsByParentExecutionId(parentId);
        for (ExecutionEntity childExecution : childExecutions) {
            List<ExecutionEntity> ccExecutions = executionEntityManager.findChildExecutionsByParentExecutionId(childExecution.getId());
            for (ExecutionEntity ccExecution : ccExecutions) {
                executionEntityManager.delete(executionEntity);
                historyManager.recordActivityEnd(executionEntity, "多实例自由跳转");
            }
            executionEntityManager.delete(childExecution);
            historyManager.recordActivityEnd(childExecution, "多实例自由跳转");
        }
        //设置目标节点
        topEntity.setCurrentFlowElement(targetElement);
        commandContext.getAgenda().planContinueProcessInCompensation(topEntity);
    }


    /**
     * 获取顶级执行实例
     *
     * @param entity 执行实例
     * @return 顶级执行实例
     */
    private ExecutionEntity getTopEntityManager(ExecutionEntity entity) {
        ExecutionEntity parent = entity.getParent();
        if (parent != null) {
            parent = parent.getParent();
            if (parent != null) {
                parent = parent.getParent();
            }
        }
        return parent == null ? entity : parent;
    }

    /**
     * 普通节点跳转
     *
     * @param executionEntity 执行实例
     * @param task            任务实体
     * @param targetElement   目标节点
     * @param commandContext
     */
    private void doNormalNodeJump(ExecutionEntity executionEntity, TaskEntity task, FlowElement targetElement, CommandContext commandContext) {
        //完成当前的任务
        HistoryManager historyManager = commandContext.getHistoryManager();
        historyManager.recordActivityEnd(executionEntity, "自由跳转");
        String taskId = task.getId();
        historyManager.recordTaskEnd(taskId, "自由跳转");
        //删除当前的任务
        commandContext.getTaskEntityManager().delete(taskId);
        //发布任务complete事件
        dispatcherEvent(commandContext, task, localScope);
        //设置目标节点
        executionEntity.setCurrentFlowElement(targetElement);
        //继续流转
        commandContext.getAgenda().planContinueProcessInCompensation(executionEntity);
    }


    /**
     * 触发任务结束事件
     *
     * @param commandContext 命令上下文
     * @param taskEntity     任务实体
     * @param localScope     是否局部变量
     */
    public void dispatcherEvent(CommandContext commandContext, TaskEntity taskEntity, Boolean localScope) {
        ActivitiEventDispatcher eventDispatcher = commandContext.getEventDispatcher();
        if (eventDispatcher.isEnabled()) {
            if (variables != null) {
                eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.TASK_COMPLETED, taskEntity, variables, localScope));
            } else {
                eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.TASK_COMPLETED, taskEntity));
            }
        }
    }

}
